package com.devbobcorn.nekoration.client.rendering;

import com.devbobcorn.nekoration.client.rendering.blockentities.PhonographRenderer;
import com.google.common.util.concurrent.Runnables;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;

import org.lwjgl.opengl.GL11;

import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;


public class RenderTypeHelper {
    @OnlyIn(Dist.CLIENT)
    public static final class BackgroundTexturingState extends RenderState.TexturingState {
        @SuppressWarnings("deprecation")
        public BackgroundTexturingState() {
            super("background", () -> {
                RenderSystem.matrixMode(5890);
                RenderSystem.pushMatrix();
                RenderSystem.loadIdentity();
                RenderSystem.translatef(0.5F, 0.5F, 0.0F);
                RenderSystem.scalef(0.5F, 0.5F, 1.0F);
                RenderSystem.mulTextureByProjModelView();
                RenderSystem.matrixMode(5888);
                RenderSystem.setupEndPortalTexGen();
            }, () -> {
                RenderSystem.matrixMode(5890);
                RenderSystem.popMatrix();
                RenderSystem.matrixMode(5888);
                RenderSystem.clearTexGen();
            });
        }

        public boolean equals(Object p_equals_1_) {
            if (this == p_equals_1_) {
                return true;
            } else if (p_equals_1_ != null && this.getClass() == p_equals_1_.getClass()) {
                return true;
            } else {
                return false;
            }
        }
    }

    public static final RenderState.AlphaState ALPHA = new RenderState.AlphaState(1F / 255F);
    public static final RenderState.CullState CULL_DISABLED = new RenderType.CullState(/*enable*/false);
    public static final RenderState.LightmapState ENABLE_LIGHTMAP = new RenderState.LightmapState(/*enable*/true);
    public static final RenderState.DepthTestState DEPTH_ALWAYS = new RenderType.DepthTestState("always", GL11.GL_ALWAYS);
    public static final RenderState.WriteMaskState COLOR_WRITE = new RenderType.WriteMaskState(/*color*/true, /*depth*/false);
    public static final RenderState.FogState NO_FOG = new RenderType.FogState("no_fog", Runnables.doNothing(), Runnables.doNothing());
    public static final RenderState.TransparencyState TRANSLUCENT = new RenderState.TransparencyState("translucent", RenderTypeHelper::enableTransparency, RenderTypeHelper::disableTransparency);
    public static final RenderState.TransparencyState ADDITIVE = new RenderState.TransparencyState(
        "additive", () -> {
            RenderSystem.enableBlend();
            RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE);
        }, RenderTypeHelper::resetTransparency);
    public static final RenderState.TransparencyState TRANSLUCENT_PLUS = new RenderState.TransparencyState(
        "translucent_plus", () -> {
            RenderSystem.enableBlend();
            RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA,
                GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE,
                GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
        }, RenderTypeHelper::resetTransparency);
    public static final RenderState.FogState DARK_FOG = new RenderState.FogState("dark_fog", RenderTypeHelper::blackFog, RenderTypeHelper::disableFog);

    private static RenderType PAINTING_PIXELS =
        RenderType.create("painting_pixels",
            DefaultVertexFormats.POSITION_COLOR_LIGHTMAP, GL11.GL_QUADS,
            /*buffer size*/256, /*no delegate*/false, /*need sorting data*/true,
            RenderType.State.builder().setAlphaState(ALPHA).setLightmapState(ENABLE_LIGHTMAP).setTransparencyState(TRANSLUCENT).createCompositeState(/*outline*/false));

    public static RenderType paintingPixels(){
        return PAINTING_PIXELS;
    }

    public static RenderType paintingTexture(ResourceLocation location){
        return RenderType.create("painting_texture",
            DefaultVertexFormats.POSITION_COLOR_TEX_LIGHTMAP, GL11.GL_QUADS,
            /*buffer size*/256, /*no delegate*/false, /*need sorting data*/true,
            RenderType.State.builder().setAlphaState(ALPHA).setLightmapState(ENABLE_LIGHTMAP).setTransparencyState(TRANSLUCENT)
                .setTextureState(new RenderState.TextureState(location, /*blur*/false, /*mipmap*/true)).createCompositeState(/*outline*/false));
    }

    public static RenderType catPortal(int layer) {
        RenderState.TransparencyState transparencystate;
        RenderState.TextureState texturestate;
        if (layer <= 1) {
           transparencystate = TRANSLUCENT_PLUS;
           texturestate = new RenderState.TextureState(PhonographRenderer.CAT_SKY, false, false);
        } else {
           transparencystate = ADDITIVE;
           texturestate = new RenderState.TextureState(PhonographRenderer.CAT_PORTAL, false, false);
        }
  
        return RenderType.create("cat_portal",
            DefaultVertexFormats.POSITION_COLOR, 7, 256, false, true, 
            RenderType.State.builder().setTransparencyState(transparencystate).setTextureState(texturestate)
                .setTexturingState(layer <= 1 ? new BackgroundTexturingState() : new RenderState.PortalTexturingState(layer)).setFogState(DARK_FOG).createCompositeState(false));
     }

    private static void enableTransparency() {
        RenderSystem.enableBlend();
        RenderSystem.defaultBlendFunc();
    }

    private static void disableTransparency() {
        RenderSystem.disableBlend();
    }

    private static void resetTransparency() {
        RenderSystem.disableBlend();
        RenderSystem.defaultBlendFunc();
    }

    @SuppressWarnings("deprecation")
    private static void blackFog() {
        RenderSystem.fog(2918, 0.0F, 0.0F, 0.0F, 1.0F);
        RenderSystem.enableFog();
    }

    @SuppressWarnings("deprecation")
    private static void disableFog() {
        FogRenderer.levelFogColor();
        RenderSystem.disableFog();
    }
}
